/*
* INSANE - Interactive Structural Analysis Environment
*
* Copyright (C) 2003-2005
* Universidade Federal de Minas Gerais
* Escola de Engenharia
* Departamento de Engenharia de Estruturas
* 
* Author's email :    insane@dees.ufmg.br
* Author's website :  http://www.dees.ufmg.br/insane
* 
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
package br.ufmg.dees.insane.materialMedia.materialPoint;

import java.io.Serializable;
import java.util.HashMap;

import br.ufmg.dees.insane.continuousPointModel.ContinuousPointModel;
import br.ufmg.dees.insane.materialMedia.constitutiveModel.ConstitutiveModel;
import br.ufmg.dees.insane.materialMedia.material.Material;
import br.ufmg.dees.insane.util.IPoint3d;
import br.ufmg.dees.insane.util.IVector;
import br.ufmg.dees.insane.util.IVolume;
import br.ufmg.dees.insane.util.geometricProperties.IGeometricPoint;

/**
 *A class representing MaterialPoint.<p>
 *
 *@author CENOURA!!!
 *@version 1.0
 *@since 04/05/2005
 */
public class MaterialPoint implements Cloneable, Serializable{

	private static final long serialVersionUID = 1L;
	
	/** The label of this MaterialPoint. */
	private String label;
    /** The IPoint3d of this MaterialPoint.*/
    private IPoint3d point;
    /** The Material of this MaterialPoint.*/
    private Material material;
    /** The ConstitutiveModel of this MaterialPoint.*/
    private ConstitutiveModel cm;
    /** The ContinuousPointModel of this MaterialPoint.*/
    private ContinuousPointModel continuousPointModel;
    /** The Volume of this MaterialPoint.*/
    private IVolume volume;
    /** The map with constitutive variables of this MaterialPoint.*/
    private HashMap<Object, Object> constitutiveVariables;
    /** The map with previous variables of this MaterialPoint used in nonlinear analysis.*/
    private HashMap<Object, Object> previousVariables;

    /**Constructs a MaterialPoint and sets its Ipoint3d.
     * @param p The IPoint3d of this MaterialPoint.
     */
    public MaterialPoint(IPoint3d p) {
        this.point=p;
        this.volume = new IVolume();
    }
    
    /**Constructs a MaterialPoint and sets its Ipoint3d and its constitutiveModel.
     * @param p The IPoint3d of this MaterialPoint.
     * @param constm The constitutiveModel of this MaterialPoint.
     */
    public MaterialPoint(IPoint3d p, ConstitutiveModel constm) {
        this.point=p;
        this.cm=constm;
        this.volume = new IVolume();
    }
    
    /**Constructs a MaterialPoint and sets its Ipoint3d, its constitutiveModel and its material.
     * @param p The IPoint3d of this MaterialPoint.
     * @param constm The constitutiveModel of this MaterialPoint.
     * @param mat The material of this MaterialPoint.
     */
    public MaterialPoint(IPoint3d p, ConstitutiveModel constm, Material mat) {
        this.point=p;
        this.cm=constm;
        this.material=mat;
        this.volume = new IVolume();
    }
    
    /**Constructs a MaterialPoint and sets its Ipoint3d, its constitutiveModel and its material.
     * @param p The IPoint3d of this MaterialPoint.
     * @param constm The constitutiveModel of this MaterialPoint.
     * @param am The AnalysisModel of this MaterialPoint. 
     * @param mat The material of this MaterialPoint.
     */
    public MaterialPoint(IPoint3d p, ConstitutiveModel constm, ContinuousPointModel am, Material mat) {
        this.point=p;
        this.cm=constm;
        this.material=mat;
        this.continuousPointModel=am;
        this.volume = new IVolume();
    }
    
    /**Constructs a MaterialPoint and sets its Ipoint3d and its area.
     * @param p The IPoint3d of this MaterialPoint.
     * @param d1 One side of this MaterialPoint area.
     * @param d2 Other side of this MaterialPoint area.
     */
    public MaterialPoint(IPoint3d p, double d1, double d2) {
        this.point=p;
        this.setArea(d1,d2);
    }
    
    /**Constructs a MaterialPoint and sets its Ipoint3d, its area and its constitutiveModel.
     * @param p The IPoint3d of this MaterialPoint.
     * @param constm The constitutiveModel of this MaterialPoint.
     * @param d1 One side of this MaterialPoint area.
     * @param d2 Other side of this MaterialPoint area.
     */
    public MaterialPoint(IPoint3d p, ConstitutiveModel constm, double d1, double d2) {
        this.point=p;
        this.cm=constm;
        this.setArea(d1,d2);
    }
    
    /**Constructs a MaterialPoint and sets its Ipoint3d, its area, its material and its constitutiveModel.
     * @param p The IPoint3d of this MaterialPoint.
     * @param constm The constitutiveModel of this MaterialPoint.
     * @param d1 One side of this MaterialPoint area.
     * @param d2 Other side of this MaterialPoint area.
     * @param mat The material of this MaterialPoint.
     */
    public MaterialPoint(IPoint3d p, ConstitutiveModel constm,  Material mat, double d1, double d2) {
        this.point=p;
        this.cm=constm;
        this.setArea(d1,d2);
        this.material=mat;
    }
    
    /**Constructs a MaterialPoint and sets its Ipoint3d, its area, its material and its constitutiveModel.
     * @param p The IPoint3d of this MaterialPoint.
     * @param constm The constitutiveModel of this MaterialPoint.
     * @param am The AnalysisModel of this MaterialPoint.
     * @param d1 One side of this MaterialPoint area.
     * @param d2 Other side of this MaterialPoint area.
     * @param mat The material of this MaterialPoint.
     */
    public MaterialPoint(IPoint3d p, ConstitutiveModel constm, ContinuousPointModel am, Material mat, double d1, double d2) {
        this.point=p;
        this.cm=constm;
        this.setArea(d1,d2);
        this.material=mat;
        this.continuousPointModel=am;
    }
    
    /**Constructs a MaterialPoint without fields.*/
        public MaterialPoint() {
            this.volume = new IVolume();
    }
    
    /**Returns the label of this MaterialPoint.
     * @return Returns the label of this MaterialPoint.
     */
    public String getLabel() {
        return label;
    }

    /** Sets the label of this MaterialPoint.
     * @param label The label to set.
     */
    public void setLabel(String label) {
        this.label = label;
    }
    /** Returns the ConstitutiveModel of this MaterialPoint.
     * @return The ConstitutiveModelof this MaterialPoint.
     */
    public ConstitutiveModel getCm() {
        return cm;
    }
    /** Sets the ConstitutiveModel of this MaterialPoint.
     * @param cm The ConstitutiveModel of this MaterialPoint.
     */
    public void setCm(ConstitutiveModel cm) {
        this.cm = cm;
    }
    
	/**
	 * @return Returns the ContinuousPointModel.
	 */
	public ContinuousPointModel getContinuousPointModel() {
		return continuousPointModel;
	}
	
	/**
	 * @param continuousPointModel The continuousPointModel to set.
	 */
	public void setContinuousPointModel(ContinuousPointModel continuousPointModel) {
		this.continuousPointModel = continuousPointModel;
	}
	
    /** Returns the material of this MaterialPoint.
     * @return Returns the material.
     */
    public Material getMaterial() {
        return material;
    }
    /** Sets the material of this MaterialPoint.
     * @param material The material to set.
     */
    public void setMaterial(Material material) {
        this.material = material;
    }
    /** Returns the IPoint3d of this MaterialPoint.
     * @return The IPoint3d of this MaterialPoint.
     */
    public IPoint3d getPoint() {
        return point;
    }
    /** Sets the IPoint3d of this MaterialPoint.
     * @param p The IPoint3d of this MaterialPoint.
     */
    public void setPoint(IPoint3d p) {
        this.point = p;
    }

    /** Sets the coordinates of this MaterialPoint.
     * @param p The array with this MaterialPoint coordinates.
     */
    public void setPoint(double y, double z) {
        IPoint3d p = new IPoint3d(0, y, z);
        this.point=p;
    }
    /** Returns the Volume of this MaterialPoint.
     * @return The Volume.
     */
    public IVolume getVolume() {
        return this.volume;
    }
    
    /** Returns the Volume Value of this MaterialPoint.
     * @return The Volume Value.
     */
    public double getVolumeValue() {
        return this.volume.volume();
    }
    
    /** Sets the volume of this MaterialPoint.
     * @param volume The volume of this MaterialPoint.
     */
    public void setVolume(double dx, double dy, double dz) {
        this.volume = new IVolume(dx, dy, dz);
    }
    
    /** Sets the volume of this MaterialPoint.
     * @param volume The volume of this MaterialPoint.
     */
    public void setVolume(IVolume v) {
        this.volume = v;
    }
    /** Sets the area of this MaterialPoint.
     * @param dx One side of this MaterialPoint area.
     * @param dy Other side of this MaterialPoint area.
     */
    public void setArea(double dy, double dz) {
        this.volume = new IVolume(dy, dz);
    }
    
    /** Sets the area of this MaterialPoint.
     * @param a The area of this MaterialPoint.
     */
    public void setArea(double a) {
        this.volume = new IVolume(a);
    }
      
    /** Returns the geometricPoint of this MaterialPoint.
     * @return Returns the geometricPoint.
     */
    public IGeometricPoint getGeometricPoint() {
        return new IGeometricPoint(this.point, this.volume);
    }
    
    /** Returns the previous variables object of this MaterialPoint.
     * @param key The key of the previous variables object of this MaterialPoint.
     * @return The previous variables object of this MaterialPoint.
     */
    public Object getPreviousVariables(String key) {
        return previousVariables.get(key);
    }
    
    /** Returns true if the MaterialPoint has the previous variables object for the key.
     * @param key The key of the previous variables object.
     * @return True if the MaterialPoint has the previous variables object for the key.
     */
    public boolean previousVariablesContainsKey(String key) {
        return previousVariables.containsKey(key);
    }
    
    /** Sets a variables object of this MaterialPoint at a key.
     * @param key The key to set the point object.
     * @param obj The object to set.
     */
    public void setPreviousVariables(String key, Object obj) {
        previousVariables.put(key, obj);
    }
    
    /** Returns the Constitutive variables object of this MaterialPoint.
     * @param key The key of the Constitutive variables object of this MaterialPoint.
     * @return The Constitutive variables object of this MaterialPoint.
     */
    public Object getConstitutiveVariables(String key) {
        return constitutiveVariables.get(key);
    }
    
    /** Returns true if the MaterialPoint has the Constitutive variables object for the key.
     * @param key The key of the Constitutive variables object.
     * @return True if the MaterialPoint has the Constitutive variables object for the key.
     */
    public boolean constitutiveContainsKey(String key) {
        return constitutiveVariables.containsKey(key);
    }
    
    /** Sets a Constitutive variables object of this MaterialPoint at a key.
     * @param key The key to set the object.
     * @param obj The object to set.
     */
    public void setConstitutiveVariables(String key, Object obj) {
        constitutiveVariables.put(key, obj);
    }
    
    /**Inits a MaterialPoint's HashMap*/
    public void init() {
        this.constitutiveVariables = new HashMap<Object, Object>(this.cm.getNumberOfVariables());
        this.previousVariables = new HashMap<Object, Object>(this.cm.getNumberOfPreviousVariables());
        this.cm.init(this.previousVariables, this.constitutiveVariables, this.continuousPointModel, this.material);
    }
    
    /** Asks to the constitutive model to update the internal variables of this material point.
    */
    public void update(){
        this.cm.update(this.previousVariables, this.constitutiveVariables);
    }
    
    /* (non-Javadoc)
     * @see java.lang.Object#clone()
     */
    public Object clone() throws CloneNotSupportedException {
        MaterialPoint mp = new MaterialPoint();
        mp.label = this.label;
        mp.point = this.point;
        mp.material = this.material;
        mp.cm = this.cm;
        mp.continuousPointModel=this.continuousPointModel;
        mp.volume = this.volume;
    	return mp;
    }
    
    /** Returns the DualInternalVariable of this MaterialPoint.
     * @param v the InternalVariable of this MaterialPoint.
     * @return The DualInternalVariable of this MaterialPoint.
     */
    public IVector getDualInternalVariables(IVector v) {
        return this.getCm().mountDualInternalVariableVector(v, this.getContinuousPointModel(), this.getMaterial(), this.getConstitutiveVariables());
    }
    
    /**
     * @return Returns the constitutiveVariables.
     */
    public HashMap<Object, Object> getConstitutiveVariables() {
        return constitutiveVariables;
    }
    /**
     * @return Returns the previousVariables.
     */
    public HashMap<Object, Object> getPreviousVariables() {
        return previousVariables;
    }
}
